<!doctype html>
<!--
@license
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<html>
<head>
  <meta charset="utf-8">
  <script src="../../../webcomponentsjs/webcomponents-lite.js"></script>
  <script src="../../../web-component-tester/browser.js"></script>
  <link rel="import" href="../../polymer.html">
  <link rel="import" href="custom-style-import.html">
  <style is="custom-style">
    x-bar {
      border: 1px solid red;
      display: block;
    }

    x-foo::shadow #bar2 {
      border: 2px solid orange;
      display: block;
    }

    x-foo::shadow #bar2::shadow #baz {
      border: 3px solid navy;
      display: block;
    }

    x-foo /deep/ #bar3 {
      border: 4px solid orange;
      display: block;
    }

    x-foo /deep/ #bar3 /deep/ #baz {
      border: 5px solid navy;
      display: block;
    }

    :root {
      --bag2: {
        border: 12px solid beige;
      };
    }

    :root {
      --red-text : {
        color : red;
      };
    }

    :root{--blue-text:{color:#0000ff};--dummy-mixin:{};--bold-text:{font-weight:700}}


    :root {

      --italic: italic;

      --bag: {
        margin: 1px;
        border: 1px solid black;
      };

      /* mocha.css in the testing environment is hosing this test;
      use !important as a workaround */
      margin: 10px !important;
      width: auto;

      --special: var(--primary);

      --after: 11px solid orange;
      @apply(--bag2);
    }

    x-foo {

      --primary: 10px;
    }

    body /deep/ * {
      --deeep: 6px solid orange;
    }
  </style>
  <style is="custom-style">
    .bag {
      ;@apply(--bag);
    }

    .italic {
      font-style: var(--italic);
    }

    .import-mixin {
      @apply(--import-mixin);
    }

    .import-var {
      border: var(--import-var);
    }

    .dynamic {
      border: var(--dynamic);
    }

    #after::after {
      content: 'after';
      border: var(--after);
    }
  </style>

  <style is="custom-style" include="shared-style2">
    .zazz {
      border: 20px solid blue;
    }
  </style>
  <style>
    .foo--bar {
      border-top : 3px solid red;
    }
  </style>
  <style is="custom-style">
    @media (min-width: 1px) {
      .foo--bar {
        border-top : 20px solid blue;
      }
    }
  </style>

  <style is="custom-style">
  :root[foo="bar"] {
    --foo: 10px dotted red;
  }
  html {
    --html: 10px dotted yellow;
  }
  html[foo="bar"] {
    --html-foo: 10px dotted green;
  }
  </style>
</head>
<body>
  <div class="italic">italic</div>
  <div class="bag">bag</div>
  <div class="mix">mix</div>

  <div class="dynamic">dynamic</div>

  <div class="import-mixin">import-mixin</div>
  <div class="import-var">import-var</div>

  <x-bar></x-bar>

  <x-foo></x-foo>

  <x-red-text></x-red-text>

  <x-blue-bold-text></x-blue-bold-text>

  <parent-variable-with-var></parent-variable-with-var>

  <br><br>
  <div id="after"></div>

  <div class="foo"></div>

  <div class="foo--bar"></div>

  <dom-module id="x-baz">
    <style>
      :host {
        display: block;
      }
    </style>
    <template>
      <div id="me">x-baz</div>
    </template>
  </dom-module>

  <dom-module id="x-bar">
    <style>
      :host {
        display: block;
      }
    </style>
    <template>
      <div>x-bar</div>
      <x-baz id="baz"></x-baz>
    </template>
  </dom-module>

  <dom-module id="x-foo">
    <style>
      :host {
        display: block;
        border: solid tomato;
        border-width: var(--special);
      }

      div {
        @apply(--bag);
      }

      #deep {
        border: var(--deeep);
      }
    </style>
    <template>
      <div id="me">x-foo</div>
      <x-bar id="bar1"></x-bar>
      <x-bar id="bar2"></x-bar>
      <x-bar id="bar3"></x-bar>
      <div id="deep">deep</div>
    </template>
  </dom-module>

  <dom-module id="x-red-text">
    <style>
      :host {
        @apply(--red-text);
      }
    </style>
    <template>
      x-red-text
    </template>
  </dom-module>

  <dom-module id="x-blue-bold-text">
    <style>
      :host {@apply(--blue-text);@apply(--bold-text);}
    </style>
    <template>
      x-blue-bold-text
    </template>
  </dom-module>

  <dom-module id="parent-variable-with-var">
    <template>
      <style>
        child-variable-with-var {
          --variable-property-own-line: 1px;
          --variable-property-preceded-property: 2px;
          --variable-property-before-property: yellow;
          --variable-property-after-property: 3px;
          --variable-property-after-assignment: 4px;
          --variable-property-before-assignment: 5px;
          --variable-into-first-variable: 9px;
          --variable-into-second-variable: 10px;
          --variable-into-third-variable: 11px;
        }
      </style>
      <child-variable-with-var id="child"></child-variable-with-var>
    </template>
  </dom-module>

  <dom-module id="child-variable-with-var">
    <template>
      <style>
        child-of-child-with-var {
          /* in certain browsers (e.g. Safari) `top`, `bottom`, `left`, `right` don't compute
             when no explicit position is defined (`relative` / `absolute` / `fixed`) */
          position: relative;
          --variable-own-line: "Varela font";
          margin-top: var(--variable-property-own-line);
          margin-bottom: var(--variable-property-preceded-property);
          --variable-between-properties: 6px;
          background-color: var(--variable-property-before-property); padding-top: var(--variable-property-after-property);
          --variable-assignment-before-property: 7px; padding-bottom: var(--variable-property-after-assignment);
          padding-left: var(--variable-property-before-assignment);--variable-assignment-after-property: 8px;
          top: 12px;--variable-from-other-variable: var(--variable-into-first-variable);--variable-from-another-variable: var(--variable-into-second-variable); --variable-from-last-variable: var(--variable-into-third-variable);
          height: 20px;
        }
      </style>
      <child-of-child-with-var id="child"></child-of-child-with-var>
    </template>
  </dom-module>

  <dom-module id="child-of-child-with-var">
    <template>
      <style>
        :host {
          font-family: var(--variable-own-line);
          padding-right: var(--variable-between-properties);
          margin-left: var(--variable-assignment-before-property);
          margin-right: var(--variable-assignment-after-property);
          bottom: var(--variable-from-other-variable);
          left: var(--variable-from-another-variable);
          right: var(--variable-from-last-variable);
        }
      </style>
      Text
    </template>
  </dom-module>

  <dom-module id="x-top-selectors">
    <template>
      <style>
      #foo {
        border: var(--foo);
      }
      #html {
        border: var(--html);
      }
      #htmlFoo {
        border: var(--html-foo);
      }
      </style>
      <div id="foo"></div>
      <div id="html"></div>
      <div id="htmlFoo"></div>
    </template>
  </dom-module>

  <script>
  HTMLImports.whenReady(function() {
    Polymer({
      is: 'x-baz'
    });

    Polymer({
      is: 'x-bar'
    });

    Polymer({
      is: 'x-foo'
    });

    Polymer({
      is: 'x-red-text'
    });

    Polymer({
      is: 'x-blue-bold-text'
    });
    Polymer({
      is: 'x-top-selectors'
    });
  })
  </script>

  <style is="custom-style">
    .order {
      @apply --order-mixin;
    }
    :root {
      --order-mixin: {
        border: 2px solid black;
      };
    }
  </style>
  <div class="order"></div>

  <script>

    suite('custom-style', function() {

      var xBar, xFoo, stylesBuilt;

      suiteSetup(function() {
        var customStyle = document.querySelector('style[is="custom-style"]');
        stylesBuilt = Polymer.StyleUtil.getCssBuildType(customStyle);

        xBar = document.querySelector('x-bar');
        xFoo = document.querySelector('x-foo');

      });

      test('root styles applied', function() {
        assertComputed(xBar, '1px');
      });

      test('root styles have lower bound encapsulation', function() {
        assertComputed(xFoo.$.bar1, '0px');
      });

      test('::shadow styles applied', function() {
        assertComputed(xFoo.$.bar2, '2px');
        assertComputed(xFoo.$.bar2.$.baz, '3px');
      });

      test('/deep/ styles applied', function() {
        assertComputed(xFoo.$.bar3, '4px');
        assertComputed(xFoo.$.bar3.$.baz, '5px');
      });

      test('custom properties registered as defaults', function() {
        var propsToCheck = ['--italic'];
        if (Polymer.Settings.useNativeCSSProperties || stylesBuilt) {
          var sep = Polymer.ApplyShim._separator;
          propsToCheck.push('--bag' + sep + 'margin', '--bag' + sep + 'border');
        } else {
          propsToCheck.push('--bag');
        }
        if (Polymer.Settings.useNativeCSSProperties) {
          var cs = getComputedStyle(document.documentElement);
          propsToCheck.forEach(function(p) {
            assert.ok(cs.getPropertyValue(p));
          });
        } else {
          var props = Polymer.StyleDefaults._styleProperties;
          propsToCheck.forEach(function(p) {
            assert.property(props, p);
          });
        }
      });

      test('custom properties with space before semicolon', function() {
        var red = document.querySelector('x-red-text');
        assertComputed(red, 'rgb(255, 0, 0)', 'color');
      });

      test('custom properties in minified css', function() {
        var blue = document.querySelector('x-blue-bold-text');
        assertComputed(blue, 'rgb(0, 0, 255)', 'color');

        var computed = getComputedStyle(blue);
        // Firefox returns `700`, while Chrome returns original `bold`
        assert.ok(computed.fontWeight == '700' || computed.fontWeight == 'bold', 'computed style incorrect for fontWeight');
      });

      test('custom-styles apply normal and property values to main document', function() {
        var bag = document.querySelector('.bag');
        var italic = document.querySelector('.italic');
        assertComputed(bag, '1px');
        assertComputed(italic, 'italic', 'font-style');
      });

      test('imported custom-styles apply', function() {
        if (stylesBuilt && !Polymer.Settings.useNativeCSSProperties) {
          // css build will test this by using vulcanize.
          // this inlines the custom-style after the consumption point, and changes the timing for custom property shim
          // Force an update style for this weird corner case in the tests
          Polymer.updateStyles();
        }
        var v = document.querySelector('.import-var');
        var m = document.querySelector('.import-mixin');
        assertComputed(v, '3px');
        assertComputed(m, '4px');
      });

      test('dynamic custom-styles apply', function() {
        var dynamic = document.querySelector('.dynamic');
        assertComputed(dynamic, '0px');
        var ds = document.createElement('style', 'custom-style');
        ds.textContent = ':root { --dynamic: 11px solid orange; }';
        document.head.appendChild(ds);
        CustomElements.takeRecords();
        Polymer.updateStyles();
        assertComputed(dynamic, '11px');
      });

      test('custom-styles apply normal and property values to elements and cannot be late bound via inheritance', function() {
        var e = document.querySelector('x-foo').$.me;
        assertComputed(e, '1px');
      });

      test('custom-styles apply to pseudo elements', function() {
        var e = document.querySelector('#after');
        assertComputed(e, '11px', null, '::after');
      });

      test('style paths in included dom-modules loaded in import', function() {
        var foo = document.querySelector('.foo');
        var url = getComputedStyle(foo).backgroundImage;
        assert.include(url, 'sub/google.png');
      });

      test('property in /deep/ rule applied via document scope inheritance', function() {
        assertComputed(xFoo.$.deep, '6px');
      });

      test('imperative custom style', function() {
        var style = document.createElement('style', 'custom-style');
        style.textContent = '.zonk { border: 13px solid tomato;}';
        var d = document.createElement('div');
        d.classList.add('zonk');
        document.body.appendChild(d);
        document.body.appendChild(style);
        CustomElements.takeRecords();
        assertComputed(d, '13px');
        document.body.removeChild(d);
        document.body.removeChild(style);
      });

      test('imperative custom style with include', function() {
        var style = document.createElement('style', 'custom-style');
        style.include = 'shared-style2';
        var d = document.createElement('div');
        d.classList.add('zazz');
        document.body.appendChild(d);
        document.body.appendChild(style);
        CustomElements.takeRecords();
        Polymer.updateStyles();
        assertComputed(d, '16px');
        document.body.removeChild(d);
        document.body.removeChild(style);
      });

      test('imperative custom style with non-existent include', function() {
        var s1 = document.createElement('style', 'custom-style');
        s1.include = 'does-not-exist';
        var style = document.createElement('style', 'custom-style');
        style.textContent = '.ziz { border: 14px solid tomato;}';
        var d = document.createElement('div');
        d.classList.add('ziz');
        document.body.appendChild(d);
        document.body.appendChild(s1)
        document.body.appendChild(style);
        CustomElements.takeRecords();
        assertComputed(d, '14px');
        document.body.removeChild(d);
        document.body.removeChild(s1);
        document.body.removeChild(style);
      });

      test('include style data applied before textContent', function() {
        var d = document.createElement('div');
        d.classList.add('zazz');
        document.body.appendChild(d);
        assertComputed(d, '20px');
        document.body.removeChild(d);
      });

      test('variable name with assignment including var correctly applied', function() {
        Polymer({
          is: 'parent-variable-with-var'
        });
        Polymer({
          is: 'child-variable-with-var'
        });
        Polymer({
          is: 'child-of-child-with-var'
        });

        var d = document.querySelector('parent-variable-with-var');
        var el = d.$.child.$.child;
        assertComputed(el, '1px', 'margin-top');
        assertComputed(el, '2px', 'margin-bottom');
        assertComputed(el, '3px', 'padding-top');
        assertComputed(el, '4px', 'padding-bottom');
        assertComputed(el, '5px', 'padding-left');
        assertComputed(el, '6px', 'padding-right');
        assertComputed(el, '7px', 'margin-left');
        assertComputed(el, '8px', 'margin-right');
        assertComputed(el, 'rgb(255, 255, 0)', 'background-color');
        assertComputed(el, '9px', 'bottom');
        assertComputed(el, '10px', 'left');
        assertComputed(el, '11px', 'right');
        assertComputed(el, '12px', 'top');

        // Because FireFox and Chrome parse font-family differently...
        var computed = getComputedStyle(el);
        assert.equal(computed['font-family'].replace(/['"]+/g, ''), 'Varela font');
      });

      test('BEM-like CSS selectors under media queries', function() {
        assertComputed(document.querySelector('.foo--bar'), '20px');
      });

      test('mixin definition and usage is ordering independant in a custom-style',
        function() {
          var el = document.querySelector('div.order');
          assertComputed(el, '2px');
        }
      );

      suite('top-level selectors', function() {
        var el;
        function activateSelectors() {
          document.documentElement.setAttribute('foo', 'bar');
          CustomElements.takeRecords();
          Polymer.updateStyles();
        }
        suiteSetup(function() {
          el = document.createElement('x-top-selectors');
          document.body.appendChild(el);
        });
        teardown(function() {
          document.documentElement.removeAttribute('foo');
          CustomElements.takeRecords();
          Polymer.updateStyles();
        });
        test(':root...', function() {
          assertComputed(el.$.foo, '0px');
          activateSelectors();
          assertComputed(el.$.foo, '10px');
        });
        test('html', function() {
          assertComputed(el.$.html, '10px');
        });
        test('html...', function() {
          assertComputed(el.$.htmlFoo, '0px');
          activateSelectors();
          assertComputed(el.$.htmlFoo, '10px');
        });
      });
    });


    function assertComputed(element, value, property, pseudo) {
      var computed = getComputedStyle(element, pseudo);
      property = property || 'border-top-width';
      assert.equal(computed[property], value, 'computed style incorrect for ' + property);
    }

  </script>

</body>
</html>
